package movee.spring.app.template.utils.jpa;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.core.annotation.AnnotationUtils;

import javax.annotation.Nonnull;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * spring jpa entity的工具类
 *
 * @author movee
 */
public class JpaEntityUtils {

    /**
     * 获取指定entity的id字段和索引字段名字集合
     * @param clazz entity类
     * @return id字段和索引字段名字集合
     */
    public static ImmutableSet<String> collectIdAndIndexFields(@Nonnull Class<?> clazz) {

        ImmutableSet.Builder<String> builder = ImmutableSet.builder();

        Set<String> indexedColumns = new HashSet<>();
        Table annoTable = AnnotationUtils.findAnnotation(clazz, Table.class);
        if (annoTable != null) {
            Index[] annoIndexes = annoTable.indexes();
            for (Index annoIndex : annoIndexes) {
                String collumList = annoIndex.columnList();
                List<String> indexFields = Splitter.on(",").omitEmptyStrings()
                        .trimResults()
                        .splitToList(collumList);
                indexedColumns.addAll(indexFields);
            }
        }

        List<Field> noColumnAnnoFields = new ArrayList<>();
        List<Field> fields = FieldUtils.getAllFieldsList(clazz);
        for (Field field : fields) {
            Column columnAnno = AnnotationUtils.findAnnotation(field, Column.class);
            if (columnAnno != null) {
                String name = columnAnno.name();
                if (indexedColumns.contains(name)) {
                    builder.add(field.getName());
                    indexedColumns.remove(name);
                }
            } else {
                noColumnAnnoFields.add(field);
            }
        }

        for (Field field : noColumnAnnoFields) {
            String name = field.getName();
            if (indexedColumns.contains(name)) {
                builder.add(name);
            }
        }

        List<Field> idFields = FieldUtils.getFieldsListWithAnnotation(clazz, Id.class);
        for (Field idField : idFields) {
            builder.add(idField.getName());
        }

        return builder.build();
    }

    /**
     * 获取entity类字段名到数据库表项列名的映射关系
     * @param clazz entity类
     * @return 类字段与表列名的映射
     */
    public static ImmutableMap<String, String> nameMap(@Nonnull Class<?> clazz) {

        ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();

        List<Field> fields = FieldUtils.getAllFieldsList(clazz);
        for (Field field : fields) {
            Column columnAnno = AnnotationUtils.findAnnotation(field, Column.class);
            if (columnAnno == null) {
                builder.put(field.getName(), field.getName());
            } else {
                builder.put(field.getName(), columnAnno.name());
            }
        }

        return builder.build();
    }

    /**
     * 获取指定entity对应的表的名字
     * @param clazz entity类
     * @return id字段和索引字段名字集合
     */
    public static String getTableName(@Nonnull Class<?> clazz) {

        Table annoTable = AnnotationUtils.findAnnotation(clazz, Table.class);
        return annoTable == null ? "" : annoTable.name();
    }

}
